package com.king.plugin.action;

import com.intellij.notification.Notification;
import com.intellij.notification.NotificationDisplayType;
import com.intellij.notification.NotificationGroup;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.vfs.VirtualFile;
import com.king.plugin.model.APIInfo;
import com.thoughtworks.qdox.JavaProjectBuilder;
import com.thoughtworks.qdox.model.JavaClass;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.io.File;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ShowActions extends AnAction {

    static final List<String> controllerAnnotations = new ArrayList<String>();
    static final Map<String, String> requestMethodAnnotations = new HashMap<String, String>();
    static {
        controllerAnnotations.add("org.springframework.web.bind.annotation.RestController");
        controllerAnnotations.add("org.springframework.stereotype.Controller");

        requestMethodAnnotations.put("org.springframework.web.bind.annotation.RequestMapping", "GET POST");
        requestMethodAnnotations.put("org.springframework.web.bind.annotation.GetMapping", "GET");
        requestMethodAnnotations.put("org.springframework.web.bind.annotation.PostMapping", "POST");
    }

    @Override
    public void actionPerformed(AnActionEvent e) {
        Project project = e.getProject();
        VirtualFile[] vFiles = ProjectRootManager.getInstance(project).getContentSourceRoots();

        JavaProjectBuilder builder =  new  JavaProjectBuilder();
        builder.setEncoding("UTF-8");
        boolean isErrorAppear = false;
        for (VirtualFile vFile : vFiles) {
            if (vFile.isDirectory()){
                try {
                    builder.addSourceTree(new File(vFile.getPath()));
                }catch(Exception es){
                    isErrorAppear = true;
                    System.out.print(es);
                }
            }
        }

        if (isErrorAppear){
            NotificationGroup notificationGroup = new NotificationGroup("DevTools", NotificationDisplayType.BALLOON, false);
            Notification notification = notificationGroup.createNotification("代码扫描时出现异常，可能导致列表不全", MessageType.WARNING);
            Notifications.Bus.notify(notification);
        }

        List<APIInfo> apiInfoList = new ArrayList<>();
        Collection<JavaClass> classes = builder.getClasses();
        classes.forEach(javaClass -> {
            boolean isController = false;
            String classPath = "";
            for (com.thoughtworks.qdox.model.JavaAnnotation javaAnnotation: javaClass.getAnnotations()) {
                if (controllerAnnotations.contains(javaAnnotation.getType().getFullyQualifiedName())){
                    isController = true;
                }else if (javaAnnotation.getType().getFullyQualifiedName().equals("org.springframework.web.bind.annotation.RequestMapping")){
                    classPath = (String)javaAnnotation.getNamedParameter("value");
                }
            }
            if (!isController){
                return;
            }

            String finalClassPath = classPath.replaceAll("\"","");
            javaClass.getMethods().forEach(javaMethod -> {
                for(com.thoughtworks.qdox.model.JavaAnnotation annotation : javaMethod.getAnnotations()) {
                    if (requestMethodAnnotations.containsKey(annotation.getType().getFullyQualifiedName())) {
                        APIInfo apiInfo = new APIInfo();
                        String pathSplit = "";
                        Object value =  annotation.getNamedParameter("value");
                        if (value instanceof String){
                            String methodPath = (String)value;
                            methodPath = methodPath.replaceAll("\"", "");
                            if (!finalClassPath.endsWith("/") && !methodPath.startsWith("/")){
                                pathSplit = "/";
                            }
                            apiInfo.setApiPath(finalClassPath + pathSplit + methodPath);
                            apiInfo.setClassDesc(parseName(javaClass.getComment()));
                            apiInfo.setClassName(javaClass.getName());
                            apiInfo.setMethodName(javaMethod.getName());
                            apiInfo.setMethodDesc(parseName(javaMethod.getComment()));
                            apiInfo.setApiMethod(requestMethodAnnotations.get(annotation.getType().getFullyQualifiedName()));
                            apiInfoList.add(apiInfo);
                        }
                    }
                }
            });
        });
        apiInfoList.sort((o1, o2) -> {
            String p1 = o1.getApiPath() == null ? "" : o1.getApiPath();
            String p2 = o2.getApiPath() == null ? "" : o2.getApiPath();
            return p1.compareToIgnoreCase(p2);
        });
        // 展示列表
        DefaultTableModel tableModel = new DefaultTableModel();
        tableModel.setColumnCount(4);
        tableModel.setRowCount(apiInfoList.size());
        tableModel.setColumnIdentifiers(new String[]{"接口路径", "接口描述", "接口位置", "请求方式"});

        com.intellij.ui.table.JBTable table = new com.intellij.ui.table.JBTable(tableModel);
        for (int i=0; i<apiInfoList.size(); i++){
            APIInfo apiInfo = apiInfoList.get(i);
            table.setValueAt("/" + apiInfo.getApiPath(), i, 0);
            table.setValueAt(apiInfo.getClassDesc() + "#" + apiInfo.getMethodDesc(), i, 1);
            table.setValueAt(apiInfo.getClassName() + "#" + apiInfo.getMethodName(), i, 2);
            table.setValueAt(apiInfo.getApiMethod(), i, 3);
        }

        JFrame frame = new JFrame("接口列表");
        frame.setSize(1200,700);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.getContentPane().add(new JScrollPane(table));
        frame.setVisible(true);
    }

    static final Pattern pattern2 = Pattern.compile("[\\u4e00-\\u9fa5_a-zA-Z0-9]{1,}");
    private String parseName(String desc){
        if (desc == null)
            return null;
        Matcher matcher = pattern2.matcher(desc);
        String name = "";
        while (matcher.find()){
            name = matcher.group();
            if (!name.equals("")){
                break;
            }
        }
        if (name.equals("")){
            name = desc;
        }
        return name;
    }
}
